package logic;

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;
import java.util.Vector;

import model.AddressBookWrapper;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class LogicElementPipe {
	
	private Log log = LogFactory.getLog(this.getClass().getCanonicalName());
	private AddressBookWrapper abook;
	private Properties pipeProps; 
	private Properties resolverProps;
	private String abookOutPath;
	private Vector <LogicElementInterface>logicElements;
	
	public LogicElementPipe(String pipePropertiesPath, 
			String resolverPropertiesPath,
			String addressBookInputFilePath,
			String addressBookOutputFilePath) throws Exception {
		
		/**
		 * parse addressbook to be performed
		 */
		abook = AddressBookWrapper.parseAddressBook(addressBookInputFilePath);
		log.info("--- parsed input address book from " + addressBookInputFilePath);		
		
		/**
		 * init
		 */
		this.init(pipePropertiesPath, resolverPropertiesPath, abook);
		
		/**
		 * write resolved address book to outfile
		 */
		abookOutPath = addressBookOutputFilePath;
		if(abookOutPath != null && abookOutPath.trim().length() > 0) {
			log.info("--- writing addressbook output to " + abookOutPath);
			try {
				abook.writeToFile(abookOutPath);
			} catch (Exception exc) {
				log.error(exc);
			}
		}
		
	}
	
	public LogicElementPipe(String pipePropertiesPath, 
			String resolverPropertiesPath,
			AddressBookWrapper abook) throws Exception {
		
		/**
		 * init
		 */
		this.init(pipePropertiesPath, resolverPropertiesPath, abook);
		
	}
	
	
	private void init(String pipePropertiesPath, 
			String resolverPropertiesPath,
			AddressBookWrapper abook) throws Exception {
		
		log.info("--- initializing processing pipeline now ...");
		
		/**
		 * load processing pipe properties from given filepath
		 */
		pipeProps = new Properties();
		pipeProps.load(new FileInputStream(new File(pipePropertiesPath)));
		
		/**
		 * load resolver properties from given filepath
		 */
		resolverProps = new Properties();
		resolverProps.load(new FileInputStream(new File(resolverPropertiesPath)));
		
		/**
		 * initializing logic elements the processing pipe consists of
		 */
		logicElements = new Vector<LogicElementInterface>();
		int numberOfLogicElements = 0;
		try {
			numberOfLogicElements = new Integer(
					pipeProps.getProperty("NUMBER_OF_LOGIC_MODULES")).
						intValue();
			log.info("pipe consists of " + numberOfLogicElements + " logic elements");
		} catch (Exception exc) {
			throw new Exception("couldn't read number of logic elements from processing pipe properties !");
		}
		
		for(int i = 0; i < numberOfLogicElements; i++) {
			String elementClassName = "CLASS_MODULE_" + i;
			String className = pipeProps.getProperty(elementClassName).trim();
			log.info("init element " + (i+1) + "/" + numberOfLogicElements +
					"now: " + className);
			LogicElementInterface module = (LogicElementInterface)
				Class.forName(className).newInstance();
			module.init(resolverProps);
			module.setAddressBook(abook);
			logicElements.add(module);
		}
		
	}
	
	public AddressBookWrapper getAddressBook() {
		return abook;
	}
	
	public void perform() {
		
		/**
		 * performing logic modules now
		 */
		long start = System.currentTimeMillis();
		log.info("--- performing processing pipeline now");
		
		for(int i = 0; i < logicElements.size(); i++) {
			LogicElementInterface module = logicElements.get(i);
			log.info("--- performing logic module: " + module.getClass().getCanonicalName());
			module.performResolving();
		}
		
		
		long processingTime = System.currentTimeMillis() - start;
		log.info("--- performed processing pipeline in msecs: " + processingTime);
		

		
	}
	
}
